package com.security.demo.custom;

import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import com.security.demo.realm.WildcardPermission;

/**
 * 在这种方法中,需要与configAttributes比较验证 1、一个对象是一个URL,一个过滤器被这个URL找到权限配置,并通过这里
 * 2、如果没有匹配相应的认证,AccessDeniedException
 * 
 */
public class MyAccessDecisionManager implements AccessDecisionManager {

	/**
	 * 在这个类中，最重要的是decide方法，如果不存在对该资源的定义，直接放行； 否则，如果找到正确的角色，即认为拥有权限，并放行，否则throw new
	 * AccessDeniedException("no right");这样，就会进入上面提到的/accessDenied.jsp页面。
	 */
	@Override
	public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		// 资源所需的角色列表，如果角色列表为空，说明不需要对该资源进行拦截，放行！
		if (CollectionUtils.isEmpty(configAttributes)) {
			return;
		}
		// 即将访问的资源URL,如 : /admin.jsp
		System.out.println(object.toString());// object is a URL.

		// 遍历所需的角色集合
		for (ConfigAttribute attribute : configAttributes) {
			String needPermission = ((SecurityConfig) attribute).getAttribute();
			// authority为用户所被赋予的权限, needPermission 为访问相应的资源应该具有的权限。
			Collection<? extends GrantedAuthority> userHasPermissions = authentication.getAuthorities();
			for (GrantedAuthority grantedAuthority : userHasPermissions) {
				if (hasPermission(grantedAuthority.getAuthority(), needPermission))
					return;
			}
		}
		// 否则，提示没有权限访问该资源
		throw new AccessDeniedException("no right");
	}

	@Override
	public boolean supports(ConfigAttribute attribute) {

		return true;
	}

	@Override
	public boolean supports(Class<?> clazz) {

		return true;
	}

	/**
	 * 判断是否包含权限
	 * 
	 * @param permission
	 *            user:*
	 * @param per
	 *            user:edit
	 * @return
	 */
	private boolean hasPermission(String permission, String per) {
		if (StringUtils.isEmpty(per)) {
			return true;
		}
		WildcardPermission p1 = new WildcardPermission(permission);
		WildcardPermission p2 = new WildcardPermission(per);
		if (p1.implies(p2) || p2.implies(p1)) {
			return true;
		}
		return false;
	}
}
